package com.quanyan.orderpay.service.impl;

import com.alibaba.fastjson.JSON;
import com.google.common.reflect.TypeToken;
import com.google.gson.Gson;
import com.google.gson.GsonBuilder;
import com.quanyan.alipay.config.AlipayConfig;
import com.quanyan.alipay.protocal.AliPayBatchTransReqData;
import com.quanyan.alipay.util.AlipaySubmit;
import com.quanyan.alipay.util.UtilDate;
import com.quanyan.api.APIRequest;
import com.quanyan.api.APIResponse;
import com.quanyan.api.enums.ApiResponseEnum;
import com.quanyan.assets.entity.TbUserAssets;
import com.quanyan.assets.request.ReqUnfreeze;
import com.quanyan.assets.response.RespBankInfo;
import com.quanyan.assets.service.UserAssetsService;
import com.quanyan.common.Plugin.Page;
import com.quanyan.common.Plugin.PageObj;
import com.quanyan.common.constants.Constants;
import com.quanyan.common.enums.BaseEnum;
import com.quanyan.common.enums.PlatformTypeEnum;
import com.quanyan.common.exception.BizException;
import com.quanyan.common.http.HttpClientUtils;
import com.quanyan.common.utils.*;
import com.quanyan.mq.client.QcMsgClient;
import com.quanyan.mq.client.reqeust.MqRequestMsg;
import com.quanyan.order.entity.Order;
import com.quanyan.order.entity.OrderRefund;
import com.quanyan.order.exception.OrderExceptionEnum;
import com.quanyan.order.service.OrderService;
import com.quanyan.orderpay.component.OrderPayRedisTemplate;
import com.quanyan.orderpay.constants.OrderMqConstants;
import com.quanyan.orderpay.entity.PaySuccessData;
import com.quanyan.orderpay.request.*;
import com.quanyan.orderpay.response.*;
import com.quanyan.orderpay.response.mq.RefundNotifyMsg;
import com.quanyan.orderpay.response.mq.WithdrawTransferNotify;
import com.quanyan.orderpay.service.OrderPayService;
import com.quanyan.orderpay.service.OrderProcessService;
import com.quanyan.orderpay.service.PayWaySettingService;
import com.quanyan.pay.entity.*;
import com.quanyan.pay.enums.*;
import com.quanyan.pay.exception.RespPayEnum;
import com.quanyan.pay.mapper.*;
import com.quanyan.pay.service.PayService;
import com.quanyan.pay.web.request.ReqPreOrder;
import com.quanyan.pay.web.request.ReqRefundRecord;
import com.quanyan.pay.web.response.RespRefundEntity;
import com.quanyan.redisCluster.utils.RedisKey;
import com.quanyan.weichat.api.WeichatServiceApi;
import com.quanyan.weichat.common.RandomStringGenerator;
import com.quanyan.weichat.common.Signature;
import com.quanyan.weichat.protocol.transfer_fund_protocal.TransferFundReqData;
import com.quanyan.weichat.protocol.transfer_fund_protocal.TransferFundResData;
import org.apache.commons.lang.math.NumberUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.BeanUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Isolation;
import org.springframework.transaction.annotation.Propagation;
import org.springframework.transaction.annotation.Transactional;

import javax.validation.Valid;
import java.io.ByteArrayInputStream;
import java.lang.reflect.Type;
import java.math.BigDecimal;
import java.text.SimpleDateFormat;
import java.util.*;

/**
 * @author songzj
 * @date 16/6/6-15:16
 */
@Service("orderPayService")
public class OrderPayServiceImpl implements OrderPayService {
    private Logger logger = LoggerFactory.getLogger(OrderPayServiceImpl.class);

    @Autowired
    private OrderService orderService;
    @Autowired
    private PayService payService;
    @Autowired
    private OrderProcessService orderProcessService;
    @Autowired
    private WithdrawApplyMapper withdrawApplyMapper;
    @Autowired
    private WithdrawRecordMapper withdrawRecordMapper;
    @Autowired
    private UserAssetsService userAssetsService;
    @Autowired
    private QcMsgClient qcMsgClient;
    @Autowired
    private PayWaySettingService payWaySettingService;
    @Autowired
    private OrderPayRedisTemplate orderPayRedisTemplate;
    @Autowired
    private WithdrawBatchMapper withdrawBatchMapper;
    @Autowired
    private EWithdrawBatchMapper eWithdrawBatchMapper;
    @Autowired
    private EBankMapper eBankMapper;
    @Autowired
    private EWithdrawApplyMapper eWithdrawApplyMapper;
    @Autowired
    private TbUnionPosRecordMapper tbUnionPosRecordMapper;

    @Override
    @Valid
    @Transactional(propagation = Propagation.REQUIRED, isolation = Isolation.READ_COMMITTED, rollbackFor = Exception.class)
    public APIResponse<RespPreOrder> submitOrder(APIRequest<ReqOrderSave> orderSaveApiRequest) {
        logger.info("业务订单号：{}。用户提交下单申请: {}。", orderSaveApiRequest.getData().getOutTradeNo(), GsonUtils.toJson(orderSaveApiRequest));
        // 检查支付方式是否可用
        Integer platform = null;
        if (orderSaveApiRequest.getData() != null) {
            platform = orderSaveApiRequest.getData().getPlatformType();
        }
        validPayIdSetting(orderSaveApiRequest.getData().getPayInfos(), platform);
        //保存订单信息及商品详情
        Order order = this.orderService.insertOrderEntity(orderSaveApiRequest);
        //订单金额不为0
        if(order.getOrderAmount().compareTo(new BigDecimal(0))==1){
            //保存支付方式和支付详情,获取第三方支付接口信息
            APIResponse<RespPreOrder> preOrderAPIResponse = insertAndPrePay(orderSaveApiRequest, order);
            //零元订单或者抵扣后零元或免密扫码支付
            if (preOrderAPIResponse.isRet() && preOrderAPIResponse.getData().getResult().equals(OrderStatusEnum.USER_PAY_SUCCESS.getCode())) {
                SimpleDateFormat sdf=new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
                logger.warn("零元订单抵扣："+order.getOrderNo());
                //支付成功后处理
                PaySuccessData paySuccessData = new PaySuccessData();
                paySuccessData.setOrderNo(order.getOrderNo());
                paySuccessData.setSourceType(OrderMqConstants.PAY_RESEND);
                paySuccessData.setPayTime(new Date());
                if (preOrderAPIResponse.getData().getPayId().equals(PayWayEnum.PAY_WAY_FOR_FREE.getPayId())) {
                    paySuccessData.setTsn("");
                    paySuccessData.setTradeType(TradeTypeEnum.TRADE_TYPE_FOR_FREE);
                }else if(preOrderAPIResponse.getData().getPayId().equals(PayWayEnum.PAY_WAY_ALIPAY_SCAN.getPayId())){
                    paySuccessData.setTsn(preOrderAPIResponse.getData().getPayTsn());
                    paySuccessData.setBuyerAccount(preOrderAPIResponse.getData().getBuyerUserId());
                    paySuccessData.setBuyerId(preOrderAPIResponse.getData().getBuyerLogonId());
                    paySuccessData.setTradeType(TradeTypeEnum.TRADE_TYPE_ALIPAY_SCAN);
                    paySuccessData.setPayTime(new Date(preOrderAPIResponse.getData().getPayTime()));
                    paySuccessData.setSellerId(preOrderAPIResponse.getData().getSellerId());
                    paySuccessData.setSellerAccount(preOrderAPIResponse.getData().getSellerAccount());
                    paySuccessData.setPayTime(new Date(preOrderAPIResponse.getData().getPayTime()));
                }else if(preOrderAPIResponse.getData().getPayId().equals(PayWayEnum.PAY_WAY_WEICHAT_SCAN.getPayId())){
                    paySuccessData.setTsn(preOrderAPIResponse.getData().getWxScanPay().get("transaction_id"));
                    paySuccessData.setBuyerAccount(preOrderAPIResponse.getData().getWxScanPay().get("openid"));
                    paySuccessData.setBuyerBank(preOrderAPIResponse.getData().getWxScanPay().get("bank_type"));
                    paySuccessData.setTradeType(TradeTypeEnum.TRADE_TYPE_WEICHAT_SCAN);
                    paySuccessData.setPayTime(new Date(preOrderAPIResponse.getData().getPayTime()));
                }
                this.orderProcessService.paySuccess(paySuccessData);
            }
            if(null!=preOrderAPIResponse.getData().getPayId()){
                this.orderService.updateOrderPayId(order.getOrderNo(),preOrderAPIResponse.getData().getPayId());
            }
            return preOrderAPIResponse;
        }else if(order.getOrderAmount().compareTo(new BigDecimal(0))==0){
            RespPreOrder respPreOrder=new RespPreOrder();
            respPreOrder.setOrderNo(order.getOrderNo());
            respPreOrder.setOutTradeNo(order.getOutTradeNo());
            respPreOrder.setResult(OrderStatusEnum.USER_PAY_SUCCESS.getCode());
            APIResponse<RespPreOrder> preOrderAPIResponse =new APIResponse<RespPreOrder>();
            respPreOrder.setPayTime(new Date().getTime());
            preOrderAPIResponse.setData(respPreOrder);
            return preOrderAPIResponse;
        }else{
            throw new BizException(OrderExceptionEnum.ORDER_AMOUNT_VALID);
        }
    }

    private void validPayIdSetting(List<ReqPayInfo> payInfos, Integer platform) {
        if (payInfos == null || payInfos.size() <= 0 || platform == null) {
            return;
        }
        String platformName = "";
        switch (platform) {
            case 1:
                platformName = PlatformTypeEnum.IOS.name();
                break;
            case 2:
                platformName = PlatformTypeEnum.ANDROID.name();
                break;
            case 3:
            case 4:
            case 6:
            case 7:
                platformName = PlatformTypeEnum.H5.name();
                break;
            default:
                return;
        }
        for (ReqPayInfo payInfo : payInfos) {
            if (PayWayEnum.PAY_WAY_ALIPAY.getPayId().equals(payInfo.getPayId()) || PayWayEnum.PAY_WAY_WEICHAT.getPayId().equals(payInfo.getPayId()) || PayWayEnum.PAY_WAY_WEICHATH5.getPayId().equals(payInfo.getPayId()) || PayWayEnum.PAY_WAY_ALIPAY_H5.getPayId().equals(payInfo.getPayId())) {
                TbPayWaySetting tbPayWaySetting = payWaySettingService.getByPayIdAndPlatform(payInfo.getPayId(), platformName);
                if (tbPayWaySetting != null && tbPayWaySetting.getEnabled() == 0) { //未开启
                    throw new BizException(OrderExceptionEnum.PAY_WAY_NOT_ENABLED);
                }
            }
        }
    }

    @Override
    @Valid
    @Transactional(propagation = Propagation.REQUIRED, isolation = Isolation.READ_COMMITTED, rollbackFor = Exception.class)
    public APIResponse<RespRefund> refund(APIRequest<ReqOrderRefund> orderRefundAPIRequest) {
        ReqOrderRefund reqOrderRefund = orderRefundAPIRequest.getData();
        String orderNo = reqOrderRefund.getOrderNo();
        logger.info("订单号：{}。用户提交退款申请: {}。", orderNo, GsonUtils.toJson(orderRefundAPIRequest));

        ReqRefundRecord reqRefundRecord = new ReqRefundRecord();
        reqRefundRecord.setOrderNo(orderNo);
        reqRefundRecord.setRefundOrderNo(CommonUtils.generateBusinessOrderNo("R", reqOrderRefund.getUid()));
        reqRefundRecord.setReason(reqOrderRefund.getReason());
        reqRefundRecord.setRefundNotifyURL(reqOrderRefund.getRefundNotifyURL());
        reqRefundRecord.setOutTradeRefundNo(reqOrderRefund.getOutTradeRefundNo());

        Order order = orderService.selectOrderByOrderNo(null, orderNo);
        reqOrderRefund.setOutTradeNo(order.getOutTradeNo());
        //支付退款记录表和支付详情退款记录表插入，发送申请退款请求给第三方支付
        APIResponse<RespRefundEntity> respRefundEntity = this.payService.insertRefundRecord(reqRefundRecord, reqOrderRefund, reqOrderRefund.getLarkAppId()); //记账并发起退款
        //订单退款表和相关产品退款表的插入
        APIResponse<OrderRefund> orderRefund = this.orderService.refundApply(reqOrderRefund, reqRefundRecord.getRefundOrderNo(),
                respRefundEntity.getData().getTotalRefundRmbAmount());
        //返回业务系统数据
        RespRefund respRefund = new RespRefund();
        respRefund.setOrderRefundNo(respRefundEntity.getData().getOrderRefundNo());
        respRefund.setOutTradeRefundNo(respRefundEntity.getData().getOutTradeRefundNo());
        //纯鸟蛋支付直接退款成功
        if (respRefundEntity.getData().getRefundStatusEnum().getCode().equals(RefundStatusEnum.SUCCESS.getCode())) {
            //退款成功处理
            RefundCompleteData refundCompleteData=new RefundCompleteData();
            refundCompleteData.setRefundOrderNo(reqRefundRecord.getRefundOrderNo());
            refundCompleteData.setResult(RefundStatusEnum.SUCCESS.getCode());
            refundCompleteData.setOrderNo(orderNo);
            refundCompleteData.setPayId(PayWayEnum.PAY_WAY_FOR_AGES.getPayId());
            orderProcessService.refundComplateProcess(refundCompleteData);
            respRefund.setResult(RefundStatusEnum.SUCCESS.getCode());
            respRefund.setRefundTime(respRefundEntity.getData().getRefundTime());
            return APIResponse.returnSuccess(respRefund);
        }
        respRefund.setResult(RefundStatusEnum.APPLY_SUBMIT.getCode());
        return APIResponse.returnSuccess(respRefund);
    }
    @Override
    @Valid
    @Transactional(propagation = Propagation.REQUIRED, isolation = Isolation.READ_COMMITTED, rollbackFor = Exception.class)
    public APIResponse<RefundStatusEnum> refundApply(APIRequest<ReqOrderRefund> orderRefundAPIRequest) {
        ReqOrderRefund reqOrderRefund = orderRefundAPIRequest.getData();
        //防止重复下单
        RedisKey redisKey = new RedisKey("orderPayRefundApply",reqOrderRefund.getOutTradeRefundNo());
        if(null!=orderPayRedisTemplate.get(redisKey)){
            return APIResponse.returnSuccess((RefundStatusEnum)orderPayRedisTemplate.get(redisKey));
        }
        String orderNo = reqOrderRefund.getOrderNo();
        logger.info("订单号：{}。用户提交退款申请: {}。", orderNo, GsonUtils.toJson(orderRefundAPIRequest));

        ReqRefundRecord reqRefundRecord = new ReqRefundRecord();
        reqRefundRecord.setOrderNo(orderNo);
        reqRefundRecord.setRefundOrderNo(CommonUtils.generateBusinessOrderNo("R", reqOrderRefund.getUid()));
        reqRefundRecord.setReason(reqOrderRefund.getReason());
        reqRefundRecord.setRefundNotifyURL(reqOrderRefund.getRefundNotifyURL());
        reqRefundRecord.setOutTradeRefundNo(reqOrderRefund.getOutTradeRefundNo());

        Order order = orderService.selectOrderByOrderNo(null, orderNo);
        reqOrderRefund.setOutTradeNo(order.getOutTradeNo());

        //支付退款记录表和支付详情退款记录表插入，发送申请退款请求给第三方支付
        APIResponse<RespRefundEntity> respRefundEntity = this.payService.insertRefundRecord(reqRefundRecord, reqOrderRefund, reqOrderRefund.getLarkAppId()); //记账并发起退款
        //订单退款表和相关产品退款表的插入
        APIResponse<OrderRefund> orderRefund = this.orderService.refundApply(reqOrderRefund, reqRefundRecord.getRefundOrderNo(),
                respRefundEntity.getData().getTotalRefundRmbAmount());
        //纯鸟蛋支付直接退款成功
        if (respRefundEntity.getData().getRefundStatusEnum().getCode().equals(RefundStatusEnum.SUCCESS.getCode())) {
            //退款成功处理
            RefundCompleteData refundCompleteData=new RefundCompleteData();
            refundCompleteData.setRefundOrderNo(reqRefundRecord.getRefundOrderNo());
            refundCompleteData.setResult(RefundStatusEnum.SUCCESS.getCode());
            refundCompleteData.setOrderNo(orderNo);
            refundCompleteData.setPayId(PayWayEnum.PAY_WAY_FOR_AGES.getPayId());
            orderProcessService.refundComplateProcess(refundCompleteData);
            orderPayRedisTemplate.set(redisKey,RefundStatusEnum.SUCCESS);
            return APIResponse.returnSuccess(RefundStatusEnum.SUCCESS);
        }
        orderPayRedisTemplate.set(redisKey,RefundStatusEnum.APPLY_SUBMIT);
        return APIResponse.returnSuccess(RefundStatusEnum.APPLY_SUBMIT);
    }

    @Override
    public APIResponse<ApiResponseEnum> auditRefundApply(APIRequest<ReqAuditEntity> auditEntityAPIRequest) {

        return null;
    }

    @Override
    @Transactional
    public APIResponse<BaseEnum> orderCancel(APIRequest<ReqOrderCancel> orderCancelAPIRequest) {
        //支付成功不可取消
        boolean payed = this.payService.checkUserPayed(orderCancelAPIRequest.getData());
        if (payed) {
            throw new BizException(RespPayEnum.ORDER_HAD_PAYED);
        }
        //订单取消
        this.orderService.cancelOrder(orderCancelAPIRequest.getData());
        //相关支付方式状态更新为取消支付
        boolean flag = this.payService.cancelOrder(orderCancelAPIRequest.getData());
        if (flag) {
            //解冻资产
            Order order = this.orderService.selectOrderByOrderNo(null, orderCancelAPIRequest.getData().getOrderNo());
            orderProcessService.unfrezenUserAssest(order, "FAIL");
        }
        return APIResponse.returnSuccess();
    }

    /**
     * 生成预支付订单, 并返回客户端.
     *
     * @param orderSaveApiRequest
     * @param order
     * @return
     */
    private APIResponse<RespPreOrder> insertAndPrePay(APIRequest<ReqOrderSave> orderSaveApiRequest, Order order) {
        ReqOrderSave orderSave = orderSaveApiRequest.getData();
        orderSaveApiRequest.getData().getPayInfos();
        ReqPreOrder reqPreOrder = new ReqPreOrder();
        reqPreOrder.setOrderNo(order.getOrderNo());
        reqPreOrder.setDescribe(order.getOrderDescribe());
        reqPreOrder.setExtraParam(order.getExtraParam());
        reqPreOrder.setMchId(order.getMchId() + "");
        reqPreOrder.setOrderAmount(order.getOrderAmount());
        reqPreOrder.setOutTradeNo(order.getOutTradeNo());
        reqPreOrder.setPayNote(order.getPayNote());
        reqPreOrder.setPayTimeOut(orderSave.getPayTimeOut());
        reqPreOrder.setReqPayInfos(orderSave.getPayInfos());
        reqPreOrder.setReturnURL(order.getNotifyUrl()); //支付成功后跳转页面.
        reqPreOrder.setShowURLForH5(orderSave.getShowURLForH5());
        reqPreOrder.setReturnUrlForH5(orderSave.getReturnUrlForH5());
        reqPreOrder.setSubject(order.getOrderSubject());
        reqPreOrder.setDescribe(order.getOrderDescribe());
        reqPreOrder.setUid(order.getUid());
        reqPreOrder.setSourceSystemId(order.getSourceSystemId());
        reqPreOrder.setSourceBusinessId(order.getSourceBusinessId());
        reqPreOrder.setBuyerAccount(orderSave.getBuyerAccount());
        reqPreOrder.setProductId(null);
        reqPreOrder.setEggInfo(orderSave.getEggInfo());
        reqPreOrder.setEggReceiver(orderSave.getEggReceiver());
        reqPreOrder.setAuthCode(orderSave.getAuthCode());
        reqPreOrder.setLarkAppId(orderSave.getLarkAppId());
        if(StringUtil.isBlankOrNull(orderSave.getUserClientIp())) {
            reqPreOrder.setUserClientIp("127.0.0.1");
        }else if(orderSave.getUserClientIp().length()<=15){
            reqPreOrder.setUserClientIp(orderSave.getUserClientIp());
        }else{
            reqPreOrder.setUserClientIp("127.0.0.1");
        }
        return this.payService.insertUserPrePay(reqPreOrder);
    }

    @Override
    @Valid
    public APIResponse<RespBatchOrderRefund>  batchRefundApply(APIRequest<ReqBatchOrderRefund> reqBatchOrderRefundAPIRequest) {
        ReqBatchOrderRefund reqBatchOrderRefund=reqBatchOrderRefundAPIRequest.getData();
        RespBatchOrderRefund respBatchOrderRefund=new RespBatchOrderRefund();
        //申请退款失败列表
        List<ReqOrderRefund> failList=new ArrayList<ReqOrderRefund>();
        APIRequest apiRequest=new APIRequest();
        for(ReqOrderRefund reqOrderRefund:reqBatchOrderRefund.getBatchOrderRefundList()){
            apiRequest.setData(reqOrderRefund);
            //调用申请退款接口
            APIResponse<RefundStatusEnum> apiResponse=refundApply(apiRequest);
            //判断申请成功与否
            if(!apiResponse.isRet()){
                failList.add(reqOrderRefund);
            }
        }
        respBatchOrderRefund.setBatchOrderRefundList(failList);
        return APIResponse.returnSuccess(respBatchOrderRefund);
    }


    @Override
    public APIResponse<RespWeichatAccount> getWeichatAccount(APIRequest<ReqWeichatAccount> reqWeichatAccountAPIRequest) {
        APIResponse<WeichatAccount> apiResponse = this.payService.getWeichatAccount(reqWeichatAccountAPIRequest.getData().getMchId(), reqWeichatAccountAPIRequest.getData().getPayId());
        RespWeichatAccount respWeichatAccount = new RespWeichatAccount();
        respWeichatAccount.setAppId(apiResponse.getData().getAppId());
        respWeichatAccount.setSecurityKey(apiResponse.getData().getSecurityKey());
        return APIResponse.returnSuccess(respWeichatAccount);
    }

    @Override
    public APIResponse<List<RespPayInfo>> selectEnablePayInfos(ReqSysPayInfo reqPayInfo) {
        APIResponse<List<PayInfo>> listAPIResponse = this.payService.selectEnablePayInfos(reqPayInfo);
        return convert2PayInfo(listAPIResponse);
    }

    @Override
    public APIResponse<List<RespPayInfo>> applyEnablePayInfos(ReqSysPayInfo reqPayInfo) {
        APIResponse<List<PayInfo>> listAPIResponse = this.payService.applyEnablePayInfos(reqPayInfo);
        return convert2PayInfo(listAPIResponse);
    }

    private APIResponse<List<RespPayInfo>> convert2PayInfo(APIResponse<List<PayInfo>> listAPIResponse) {
        List<RespPayInfo> respPayInfos = new ArrayList<>();
        RespPayInfo respPayInfo = null;
        for (PayInfo payInfo : listAPIResponse.getData()) {
            respPayInfo = new RespPayInfo();
            BeanUtils.copyProperties(payInfo, respPayInfo);
            respPayInfos.add(respPayInfo);
        }
        return APIResponse.returnSuccess(respPayInfos);
    }



    private void sendNotify(String notifyUrl, WithdrawTransferNotify notify, String messageId){
        if (!StringUtil.isBlankOrNull(notifyUrl)) {     //如果有回调url，优先使用过会的url
            try {
                HttpClientUtils.postJson(notifyUrl, JSON.toJSONString(notify));
            } catch (Exception e) {
                logger.error("发送提现付款通知失败！{}", e.getMessage());
            }
            logger.info("发送提现付款回调消息：{}", JSON.toJSONString(notify));
        }else {
            MqRequestMsg mqRequestMsg = new MqRequestMsg();
            mqRequestMsg.setTopic(OrderPayService.TOPIC_WITHDRAW_CALLBACK_NOTIFY);
            mqRequestMsg.setTag("*");
            mqRequestMsg.setMsgId(messageId);
            mqRequestMsg.setFlag(0);
            mqRequestMsg.setBody(ObjectUtil.toByteArray(notify));
            qcMsgClient.asyncSend(mqRequestMsg);
            logger.info("发送提现付款回调消息：{}", JSON.toJSONString(notify));
        }
    }


    /**
     * 提现申请
     */
    @Override
    public APIResponse applyWithdraw(ReqWithdrawApply reqWithdrawApply) {
        logger.warn("收到提现申请，参数：" + JSON.toJSONString(reqWithdrawApply));

        if (StringUtil.isBlankOrNull(reqWithdrawApply.getSourceSystemCode())){
            return APIResponse.returnFail("系统编号不能为空");
        }
        if (StringUtil.isBlankOrNull(reqWithdrawApply.getSourceBusinessCode())){
            return APIResponse.returnFail("系统业务编号不能为空");
        }
        if (reqWithdrawApply.getWithdrawPayInfo() == null){
            return APIResponse.returnFail(ApiResponseEnum.PARAMETER_CANT_BE_EMPTY);
        }
        WithdrawPayInfo withdrawPayInfo = reqWithdrawApply.getWithdrawPayInfo();
        if (StringUtil.isBlankOrNull(withdrawPayInfo.getAccountNo())){
            return APIResponse.returnFail("收款人账号不能为空");
        }
        if (StringUtil.isBlankOrNull(withdrawPayInfo.getApplyNo())){
            return APIResponse.returnFail("提现申请号不能为空");
        }
        if (StringUtil.isBlankOrNull(withdrawPayInfo.getName())){
            return APIResponse.returnFail("收款人姓名不能为空");
        }
        if (withdrawPayInfo.getAmount() == null || withdrawPayInfo.getAmount().doubleValue() <= 0){
            return APIResponse.returnFail("提现金额不能小于0");
        }
        if(null!=reqWithdrawApply.getPayType()&&reqWithdrawApply.getPayType().intValue()==2&&withdrawPayInfo.getAmount().compareTo(new BigDecimal(1))==-1){
            return APIResponse.returnFail("微信提现最低不能小于1元");
        }
        if (withdrawPayInfo.getApplyTime() == null){
            return APIResponse.returnFail("用户提现申请时间不能为空");
        }

        //获取付款账号
        int payType = reqWithdrawApply.getPayType();
        String payAccountNo = null;
        String accountVersion = "2";
        String appversion = reqWithdrawApply.getAppVersion();
        if(appversion != null && appversion.equals("2.0.0.1")){
            accountVersion = "3";
        }
        if (payType == 1) {
            APIResponse<AlipayAccount> accountResp = payService.getAlipayAccount(accountVersion, PayWayEnum.PAY_WAY_ALIPAY.getPayId());
            if (!accountResp.isRet()) {
                return accountResp;
            }
            AlipayAccount payAccount = accountResp.getData();
            if (payAccount != null) {
                payAccountNo = payAccount.getSeller();
            }
        } else if (payType == 2) {
            APIResponse<WeichatAccount> accountResp = payService.getWeichatAccount(accountVersion, PayWayEnum.PAY_WAY_WEICHAT.getPayId());
            if (!accountResp.isRet()) {
                return accountResp;
            }
            WeichatAccount payAccount = accountResp.getData();
            payAccountNo = payAccount.getMchId();
        } else {
            payAccountNo = "123456";
        }

        //插入提现申请记录
        String systemCode = reqWithdrawApply.getSourceSystemCode();
        String businessCode = reqWithdrawApply.getSourceBusinessCode();

        WithdrawApply withdrawApply = new WithdrawApply();
        withdrawApply.setSourceSystemCode(systemCode);
        withdrawApply.setSourceBusinessCode(businessCode);
        withdrawApply.setWithdrawAccountNo(withdrawPayInfo.getAccountNo());
        withdrawApply.setWithdrawAmount(withdrawPayInfo.getAmount());
        withdrawApply.setWithdrawUserName(withdrawPayInfo.getName());
        withdrawApply.setWithdrawApplyNo(withdrawPayInfo.getApplyNo());
        withdrawApply.setWithdrawApplyTime(withdrawPayInfo.getApplyTime());
        withdrawApply.setPayType((byte) payType);
        withdrawApply.setPayAccountNo(payAccountNo);
        withdrawApply.setAuditStatus((byte) 0);
        withdrawApply.setStatus((byte) 0);
        withdrawApply.setNotifyUrl(reqWithdrawApply.getNotifyUrl());
        withdrawApply.setBalance(withdrawPayInfo.getBalance());
        withdrawApply.setPhone(withdrawPayInfo.getPhone());
        withdrawApply.setRemark(withdrawPayInfo.getRemark());
        withdrawApply.setClubId(withdrawPayInfo.getClubId());
        withdrawApply.setLarkAppId(withdrawPayInfo.getLarkAppId()==1?1:withdrawPayInfo.getLarkAppId());
        if(systemCode.equals(Constants.CLUB_SYSTEM_CODE)){
            withdrawApply.setBusinessId(withdrawPayInfo.getClubId());
        }else{
            withdrawApply.setBusinessId(withdrawPayInfo.getBusinessId());
        }
        withdrawApply.setAppVersion(Integer.valueOf(accountVersion)); //记录版本号
        withdrawApply.setWithdrawDesc(withdrawPayInfo.getWithdrawDesc()==null?"百灵鸟资金入账":withdrawPayInfo.getWithdrawDesc().replaceAll("\\^",""));
        if(null!=withdrawPayInfo.getBalance()&&withdrawPayInfo.getBalance().compareTo(new BigDecimal(0))==-1){
            return APIResponse.returnFail("账户余额不能小于0");
        }
        withdrawApplyMapper.insertSelective(withdrawApply);
        logger.info("返回支付系统提现申请流水号：" + withdrawApply.getWithdrawNo());
        return APIResponse.returnSuccess(withdrawApply.getWithdrawNo());
    }

    @Value("${ali.pay.withdraw.callback}")
    private String withdrawNotifyUrl;

    /**
     * 批量付款，支付宝批量付款到支付宝账户有密接口，生成提交表单，返回html表单给前端提交批量付款信息
     */
    @Override
    @Transactional(rollbackFor = Exception.class)
    public APIResponse batchTrans(ReqWithdrawFormData reqWithdrawTransferData) {
        Gson gson = new GsonBuilder().create();
        logger.info("批量打款请求数据："+gson.toJson(reqWithdrawTransferData));
//        //按批次打款(作废)
//        if(null!=reqWithdrawTransferData.getBatchNo()){
//            WithdrawBatch withdrawBatch = eWithdrawBatchMapper.selectByBatchNo(reqWithdrawTransferData.getBatchNo());
//            if(null == withdrawBatch){
//                return APIResponse.returnFail("无该批次号的打款记录");
//            }else{
//                Type mapDataType = new TypeToken<Map<String, String>>(){}.getType();
//                //直接获取打款记录
//                Map<String, String> returnMap=gson.fromJson(withdrawBatch.getResult(), mapDataType);
//                return APIResponse.returnSuccess(returnMap);
//            }
//        }

        //1. 生成付款详细信息, 格式为：流水号1^收款方账号1^收款账号姓名1^付款金额1^备注说明1|流水号2^收款方账号2^收款账号姓名2^付款金额2^备注说明2。
        StringBuilder payDetailData = new StringBuilder();
        List<WithdrawPayInfo> withdrawPayInfos = reqWithdrawTransferData.getWithdrawPayInfos();
        if (withdrawPayInfos == null || withdrawPayInfos.size() == 0){
            return APIResponse.returnFail("无付款信息");
        }
        //支付宝付款笔数
        int batchNum = 0;
        BigDecimal batchFee = BigDecimal.ZERO;
        //微信或支付宝
        Boolean threeFlag=false;
        //银联
        Boolean unionFlag=false;
        //银联和第三方不能混合
        for (int i = 0; i < withdrawPayInfos.size(); i++) {
            WithdrawPayInfo payInfo = withdrawPayInfos.get(i);
            if (null == payInfo.getPayType()) {

            }else if(payInfo.getPayType()==1||payInfo.getPayType()==2){
                threeFlag = true;
            }else{
                unionFlag = true;
            }
        }
        if(unionFlag && threeFlag){
            return APIResponse.returnFail("银联不可与其他支付方式同时付款！");
        }

        StringBuilder withdrawNos = new StringBuilder();
        for (int i = 0; i < withdrawPayInfos.size(); i++) {
            WithdrawPayInfo payInfo = withdrawPayInfos.get(i);
            WithdrawApply apply = withdrawApplyMapper.selectByPrimaryKey(Integer.valueOf(payInfo.getWithdrawNo()));
            if (apply == null){
                throw new BizException(RespPayEnum.WITHDRAW_RECORD_IS_NULL);
            }
            if(payInfo.getPayAmount().compareTo(apply.getWithdrawAmount())>0){
                throw new BizException(RespPayEnum.INVALID_WITHDRAW_AMOUNT);
            }
            if(null==payInfo.getPayType()){

            }else if(payInfo.getPayType()==1){

                //支付宝批量付款
                batchFee = batchFee.add(payInfo.getAmount());
                //单条付款信息
                StringBuilder sb = new StringBuilder();
                sb.append(payInfo.getWithdrawNo());  //流水号用支付系统生成的提现申请流水号
                sb.append("^");
                sb.append(payInfo.getAccountNo());
                sb.append("^");
                sb.append(payInfo.getName());
                sb.append("^");
                BigDecimal payAmount = payInfo.getPayAmount();
                sb.append(payAmount);
                //更新状态为第三方处理中
                updateWithdrawApplyStatus(apply, payInfo.getPayOpInfo(),payInfo.getPayType());
                sb.append("^");
                sb.append(payInfo.getWithdrawDesc().replaceAll("\\^","")); //备注为申请提现时间
                payDetailData.append(sb.toString());
                withdrawNos.append(payInfo.getWithdrawNo());
                if (i != withdrawPayInfos.size() - 1) {
                    payDetailData.append("|");
                    withdrawNos.append(",");
                }
                batchNum=batchNum+1;
            }else if(payInfo.getPayType()==2){
                //更新状态为系统处理中
                updateWithdrawApplyStatus(apply, payInfo.getPayOpInfo(),payInfo.getPayType());
                //把微信提现放到MQ
                MqRequestMsg mqRequestMsg = new MqRequestMsg();
                mqRequestMsg.setTopic(OrderMqConstants.ORDER_TOPIC_WITHDRAW_WECHAT);
                mqRequestMsg.setTag(Constants.ORDER_SYSTEM_CODE);
                mqRequestMsg.setMsgId(payInfo.getAccountNo());
                mqRequestMsg.setBody(ObjectUtil.toByteArray(payInfo));
                qcMsgClient.asyncSend(mqRequestMsg);
                continue;
            }else {
                //银联更新状态
                int count = eWithdrawApplyMapper.updateBankSuccessByWithdrawNo(payInfo.getWithdrawNo());
                if(count != 0){
                    WithdrawApply withdrawApply = withdrawApplyMapper.selectByPrimaryKey(Integer.valueOf(payInfo.getWithdrawNo()));
                    //处理付款结果
                    WithdrawTransferNotify notify = new WithdrawTransferNotify();
                    notify.setSourceSystemCode(withdrawApply.getSourceSystemCode());
                    notify.setSourceBusinessCode(withdrawApply.getSourceBusinessCode());
                    notify.setWithdrawNo(withdrawApply.getWithdrawNo().toString());
                    notify.setApplyNo(withdrawApply.getWithdrawApplyNo());
                    notify.setAmount(payInfo.getPayAmount());    //回调返回单位为元
                    notify.setAccountNo(withdrawApply.getWithdrawAccountNo());
                    notify.setName(withdrawApply.getWithdrawUserName());
                    notify.setCompletedTime(new SimpleDateFormat("yyyy-MM-dd HH:mm:ss").format(new Date()));
                    notify.setTsn(null);  //第三方流水号
                    notify.setTag(true);
                    notify.setReason("付款成功");
                    notify.setNotifyUrl(withdrawApply.getNotifyUrl());
                    orderProcessService.callBackByWithdraw(notify,OrderMqConstants.PAY_RESEND);
                }

            }

        }
        if(batchNum==0){
            //付款成功(纯微信)
            return APIResponse.returnSuccess();
        }else{
            payDetailData.substring(0,payDetailData.length()-1);
            withdrawNos.substring(0,withdrawNos.length()-1);
        }

        //2. 生成付款批次号
        String seqNo = CommonUtils.generateOrderNo(1000);
        if (seqNo.length() > 24) {
            seqNo = seqNo.substring(0, 23);
        }
        String batchNo = UtilDate.getDate() + seqNo; //保证唯一

        //3. 获取公司的支付宝账户信息
        APIResponse<AlipayAccount> accountResp = payService.getAlipayAccount("2", PayWayEnum.PAY_WAY_ALIPAY.getPayId());
        if (!accountResp.isRet()) {
            return accountResp;
        }
        AlipayAccount alipayAccount = accountResp.getData();

        //4. 组装支付宝批量付款到支付宝账户有密接口所需参数
        AliPayBatchTransReqData reqData = new AliPayBatchTransReqData();
        reqData.setPartner(alipayAccount.getPartner());
        reqData.set_input_charset(alipayAccount.getInputCharset()); // UTF-8
        reqData.setSign_type(alipayAccount.getSignType());
        reqData.setNotify_url(withdrawNotifyUrl);
        reqData.setAccount_name("深圳市泉眼网络科技有限公司");
        reqData.setDetail_data(payDetailData.toString());
        reqData.setBatch_no(batchNo);
        reqData.setBatch_num(String.valueOf(batchNum));
        reqData.setBatch_fee(String.valueOf(batchFee.doubleValue()));
        reqData.setEmail(alipayAccount.getSeller());
        reqData.setPay_date(UtilDate.getDate());

        //5. 生成批量付款请求HTML表单
        AlipayConfig alipayConfig = new AlipayConfig.Builder()
                .setKey(alipayAccount.getAliKey())
                .build();
        String result = AlipaySubmit.buildRequest(ObjectUtil.objectToMapString(reqData),
                reqWithdrawTransferData.getFormMethod(), reqWithdrawTransferData.getFormSubmitButtonName(), alipayConfig);

        //6. 生成支付宝批量打款记录
//        WithdrawRecord withdrawRecord = new WithdrawRecord();
//        withdrawRecord.setBatchNo(batchNo);
//        withdrawRecord.setBatchNum(batchNum);
//        withdrawRecord.setWithdrawNo(withdrawNos.toString());
//        withdrawRecord.setStatus((byte) 0); //返回了提交表单，跳到支付宝批量付款页面，但不一定付了款
//        withdrawRecordMapper.insert(withdrawRecord);
        WithdrawBatch withdrawBatch = new WithdrawBatch();
        withdrawBatch.setBatchNo(batchNo);
        withdrawBatch.setApplyNum(batchNum);
        withdrawBatch.setWithdrawNos(withdrawNos.toString());
        withdrawBatch.setStatus((byte)1);
        withdrawBatch.setSumAmount(batchFee);
        //7. 返回结果
        Map<String, String> resultMap = new HashMap<>();
        resultMap.put("batchNo", batchNo);      //付款批次号
        resultMap.put("form", result);          //表单信息
        withdrawBatch.setResult(gson.toJson(resultMap));
        withdrawBatchMapper.insert(withdrawBatch);
        return APIResponse.returnSuccess(resultMap);
    }

    private void updateWithdrawApplyStatus(WithdrawApply apply, String payOpInfo,Byte payType){
        WithdrawApplyExample withdrawApplyExample=new WithdrawApplyExample();
        WithdrawApplyExample.Criteria criteria=withdrawApplyExample.createCriteria();
        criteria.andWithdrawNoEqualTo(apply.getWithdrawNo());
        List<Byte> statusList=new ArrayList<Byte>();
        statusList.add((byte)0);
        statusList.add((byte)3);
        criteria.andStatusIn(statusList);
        apply.setPayOpInfo(payOpInfo+"@"+DateUtils.convertDateFormatToString(new Date()));
        if(payType.byteValue()==2){
            apply.setStatus((byte)5);
        }else{
            apply.setStatus((byte)1);
        }
        apply.setUpdateTime(new Date());
        int count=withdrawApplyMapper.updateByExampleSelective(apply,withdrawApplyExample);
        if(count==0){
            throw new BizException(RespPayEnum.INVALID_WITHDRAW);
        }

    }

    private void updateWithdrawApplyPayInfo(int withdrawNo, String payOpInfo){
        WithdrawApply apply = withdrawApplyMapper.selectByPrimaryKey(withdrawNo);
        if (apply == null){
            throw new BizException(RespPayEnum.WITHDRAW_RECORD_IS_NULL);
        }
        WithdrawApplyExample withdrawApplyExample=new WithdrawApplyExample();
        WithdrawApplyExample.Criteria criteria=withdrawApplyExample.createCriteria();
        criteria.andWithdrawNoEqualTo(apply.getWithdrawNo());
        List<Byte> statusList=new ArrayList<Byte>();
        statusList.add((byte)0);
        statusList.add((byte)3);
        criteria.andStatusIn(statusList);
        apply.setPayOpInfo(payOpInfo+"@"+DateUtils.convertDateFormatToString(new Date()));
        apply.setStatus((byte)1);
        apply.setUpdateTime(new Date());
        int count=withdrawApplyMapper.updateByExampleSelective(apply,withdrawApplyExample);
        if(count==0){
            throw new BizException(RespPayEnum.INVALID_WITHDRAW);
        }

    }

    /**
     * 提现申请列表
     */
    @Override
    public APIResponse queryApplyWidthdrawList(ReqWithdrawApplyList reqWithdrawApplyList) {

        Date startTime = reqWithdrawApplyList.getStartDate();
        Date endTime = reqWithdrawApplyList.getEndDate();
        //付款时间
        Date startDealTime = reqWithdrawApplyList.getStartDealTime();
        Date endDealTime = reqWithdrawApplyList.getEndDealTime();
        if (startTime != null && endTime != null
                && startTime.compareTo(endTime) > 1){
            return APIResponse.returnFail("申请开始时间晚于结束时间！");
        }

        WithdrawApplyExample example = new WithdrawApplyExample();


        WithdrawApplyExample.Criteria criteria = example.createCriteria();
        if (startTime != null){
            criteria.andWithdrawApplyTimeGreaterThanOrEqualTo(startTime);
        }
        if (endTime != null){
            criteria.andWithdrawApplyTimeLessThan(DateUtils.addNDay(endTime,1));
        }
        if(null != startDealTime){
            criteria.andDealTimeGreaterThanOrEqualTo(startDealTime);
        }
        if(null != endDealTime){
            criteria.andDealTimeLessThan(DateUtils.addNDay(endDealTime,1));
        }
        //第三方处理结果
        String result = reqWithdrawApplyList.getResult();
        if (!StringUtil.isBlankOrNull(result)){
            criteria.andResultLike("%"+result+"%");
        }
        String applyNo = reqWithdrawApplyList.getApplyNo();
        if (!StringUtil.isBlankOrNull(applyNo)){
            criteria.andWithdrawApplyNoLike("%"+applyNo+"%");
        }
        String name = reqWithdrawApplyList.getRealName();
        if (!StringUtil.isBlankOrNull(name)){
            criteria.andWithdrawUserNameLike("%"+name+"%");
        }
        Integer moudleId = reqWithdrawApplyList.getModuleId();
        if (moudleId == 1) {
            criteria.andSourceBusinessCodeEqualTo(Constants.CLUB_WITHDRAW_BUSINESS_CODE);
        }
        if (moudleId == 2){
            criteria.andSourceSystemCodeEqualTo(Constants.AUCTION_SYSTEM_CODE);
        }
        if (moudleId == 3){
            criteria.andSourceSystemCodeEqualTo(Constants.ONEPRICE_SYSTEM_CODE);
        }
        if (moudleId == 4){
            criteria.andSourceBusinessCodeEqualTo("PLACE_SUPPLIER_EXTRACT_CODE");
        }
        if (moudleId == 5){
            criteria.andSourceBusinessCodeEqualTo("PLACE_PROMOTE_EXTRACT_CODE");
        }
        if (moudleId == 6){
            criteria.andSourceBusinessCodeEqualTo(Constants.CLUB_CHANNEL_WITHDRAW_BUSINESS_CODE);
        }
        if (moudleId == 7){
            criteria.andSourceBusinessCodeEqualTo("DAREN_SPARRING_WITHDRAW_BUSSINESS_CODE");
        }
        String phone = reqWithdrawApplyList.getPhone();
        if (!StringUtil.isBlankOrNull(phone)){
            criteria.andPhoneLike("%"+phone+"%");
        }
        String accountNo = reqWithdrawApplyList.getAccountNo();
        if (!StringUtil.isBlankOrNull(accountNo)){
            criteria.andWithdrawAccountNoLike("%"+accountNo+"%");
        }
        Integer payType = reqWithdrawApplyList.getPayType();
        if(null != payType && payType.intValue()!=0){
            if(payType.intValue() != 1&&payType.intValue() != 2){
                List<Byte> payTypeList = new ArrayList<Byte>();
                payTypeList.add((byte)1);
                payTypeList.add((byte)2);
                criteria.andPayTypeNotIn(payTypeList);
            }else{
                criteria.andPayTypeEqualTo(payType.byteValue());
            }
        }
        List<Byte> status = reqWithdrawApplyList.getStatus();
        if (status != null && status.size() != 0){
            criteria.andStatusIn(status);
        }

        //int itemsCount = withdrawApplyMapper.countByExample(example);

        int total = withdrawApplyMapper.countByExample(example);
        List<WithdrawApply> itemsList = withdrawApplyMapper.selectByExample(example);
        BigDecimal totalAmount = BigDecimal.ZERO;
        for (WithdrawApply item : itemsList){
            totalAmount = totalAmount.add(item.getWithdrawAmount());
        }
        example.setOrderByClause(" create_time desc");

        int pageNo = reqWithdrawApplyList.getPageNo();
        int pageSize = reqWithdrawApplyList.getPageSize();
        example.setPage(new Page(pageNo*pageSize, pageSize));

        List<WithdrawApply> resultList = withdrawApplyMapper.selectByExample(example);
        List<RespWithdrawApply> list = new ArrayList<>();
        for (WithdrawApply withdrawApply : resultList){
            RespWithdrawApply apply = new RespWithdrawApply();
            apply.setAccountNo(withdrawApply.getWithdrawAccountNo());
            apply.setAmount(withdrawApply.getWithdrawAmount());
            apply.setApplyNo(withdrawApply.getWithdrawApplyNo());
            apply.setApplyTime(withdrawApply.getWithdrawApplyTime());
            String syscode = withdrawApply.getSourceSystemCode();
            if (Constants.CLUB_WITHDRAW_BUSINESS_CODE.equals(withdrawApply.getSourceBusinessCode())){
                apply.setModuleId(1);
            }
            if (Constants.AUCTION_SYSTEM_CODE.equals(syscode)){
                apply.setModuleId(2);
            }
            if (Constants.ONEPRICE_SYSTEM_CODE.equals(syscode)){
                apply.setModuleId(3);
            }
            if ("PLACE_SUPPLIER_EXTRACT_CODE".equals(withdrawApply.getSourceBusinessCode())){
                apply.setModuleId(4);
            }
            if ("PLACE_PROMOTE_EXTRACT_CODE".equals(withdrawApply.getSourceBusinessCode())){
                apply.setModuleId(5);
            }
            if (Constants.CLUB_CHANNEL_WITHDRAW_BUSINESS_CODE.equals(withdrawApply.getSourceBusinessCode())){
                apply.setModuleId(6);
            }
            if ("DAREN_SPARRING_WITHDRAW_BUSSINESS_CODE".equals(withdrawApply.getSourceBusinessCode())){
                apply.setModuleId(7);
            }
            apply.setBusinessId(withdrawApply.getBusinessId());
            apply.setPayType(withdrawApply.getPayType());
            apply.setRealName(withdrawApply.getWithdrawUserName());
            apply.setStatus(withdrawApply.getStatus());
            apply.setBalance(withdrawApply.getBalance());
            apply.setRemark(withdrawApply.getRemark());
            apply.setPhone(withdrawApply.getPhone());
            apply.setWithdrawNo(String.valueOf(withdrawApply.getWithdrawNo()));
            apply.setResult(withdrawApply.getResult());
            apply.setPayOpInfo(withdrawApply.getPayOpInfo());
            apply.setPayAmount(withdrawApply.getPayAmount());
            apply.setCreateTime(withdrawApply.getCreateTime());
            apply.setUpdateTime(withdrawApply.getUpdateTime());
            apply.setClubId(withdrawApply.getClubId());
            apply.setWithdrawDesc(withdrawApply.getWithdrawDesc());
            apply.setDealTime(withdrawApply.getDealTime());
            list.add(apply);
        }

        PageObj<List<RespWithdrawApply>> pageObj = PageObj.create(total, pageNo, pageSize, list);
        RespWithdrawApplyPage page = new RespWithdrawApplyPage();
        //   page.setItemsCount(itemsCount);
        page.setItemsTotalAmount(totalAmount);
        page.setPageObj(pageObj);
        return APIResponse.returnSuccess(page);
    }

    @Override
    @Valid
    public APIResponse<RespOrderInfo> orderQuery(APIRequest<ReqOrderInfo> reqOrderAPIRequest) {
        ReqOrderInfo reqOrderInfo=reqOrderAPIRequest.getData();
        if(null==reqOrderInfo.getOrderNo()&&null==reqOrderInfo.getOutTradeNo()){
            throw new BizException(OrderExceptionEnum.ORDER_NO_NULL);
        }
        //获取订单信息
        Order order=orderService.selectByOrderInfo(reqOrderInfo);
        RespOrderInfo respOrderInfo=new RespOrderInfo();
        respOrderInfo.setOrderAmount(order.getOrderAmount());
        respOrderInfo.setUid(order.getUid());
        respOrderInfo.setOrderState(order.getOrderState());
        //获取支付详情
        List<PayRecordDetail> payRecordDetails = this.payService.selectPayRecordDetailByOrderNo(order.getOrderNo());
        TSNRecord tsnRecord=this.payService.selectTsnRecord(order.getOrderNo());
        if(null!=tsnRecord){
            respOrderInfo.setPayTsn(tsnRecord.getTsn());
        }
        List<RefundRecord> refundRecordList=this.payService.selectRefundRecordByOrderNo(order.getOrderNo());
        List<RefundNotifyMsg> refundList=new ArrayList<RefundNotifyMsg>();
        RefundNotifyMsg refundNotifyMsg=null;
        if(null!=refundRecordList) {
            for (RefundRecord refundRecord : refundRecordList) {
                refundNotifyMsg = new RefundNotifyMsg();
                refundNotifyMsg.setRefundOrderNo(refundRecord.getRefundOrderNo());
                refundNotifyMsg.setOutTradeRefundOrderNo(refundRecord.getOutTradeRefundNo());
                refundNotifyMsg.setTsnRefundNo(refundRecord.getTsnRefundNo());
                refundList.add(refundNotifyMsg);
            }
        }
        respOrderInfo.setRefundList(refundList);
        List<ReqPayInfo> reqPayInfos = new ArrayList<ReqPayInfo>();
        ReqPayInfo reqPayInfo = null;
        if(null!=payRecordDetails) {
            for (PayRecordDetail payRecordDetail : payRecordDetails) {
                reqPayInfo = new ReqPayInfo();
                reqPayInfo.setPayId(payRecordDetail.getPayId());
                reqPayInfo.setAmount(payRecordDetail.getPayAmount());
                reqPayInfos.add(reqPayInfo);
            }
        }
        respOrderInfo.setPayInfoList(reqPayInfos);
        return APIResponse.returnSuccess(respOrderInfo);
    }

    @Override
    public APIResponse<List<RespOrderInfo>> orderQueryBacth(List<String> orderList) {
        return this.payService.orderQueryBacth(orderList);
    }


    /**
     * 微信企业付款，从指定商户付款给用户
     */
    @Override
    public APIResponse transferFundByWechat(WithdrawPayInfo payInfo) {

        String openid = payInfo.getAccountNo();     //商户appid下，某用户的openid
        String withdrawNo = payInfo.getWithdrawNo();    //支付系统申请提现流水号
        BigDecimal amount = payInfo.getAmount().multiply(new BigDecimal(100));      //提现申请金额，单位为分，变为元
        BigDecimal payAmount = payInfo.getPayAmount().multiply(new BigDecimal(100)); //企业付款实际打款金额，单位为元
        String desc = "提现";

        if (StringUtil.isBlankOrNull(openid) || StringUtil.isBlankOrNull(withdrawNo)
                || payAmount == null || (payAmount.doubleValue() <= 0) || StringUtil.isBlankOrNull(desc)) {
            return APIResponse.returnFail(ApiResponseEnum.PARAMETER_CANT_BE_EMPTY);
        }
        if (!NumberUtils.isDigits(withdrawNo)) {
            return APIResponse.returnFail(ApiResponseEnum.PARAMETER_INVALID);
        }
        //判断此提现申请是否存在
        WithdrawApply apply = withdrawApplyMapper.selectByPrimaryKey(Integer.valueOf(withdrawNo));
        if (apply == null) {
            return APIResponse.returnFail("支付系统未检查到提现申请号为[" + withdrawNo + "]的提现申请记录");
        } else {
            //如果已经付款成功了，不能再次提现，防止一此提现申请被重复提现多次
            if (apply.getStatus() == 2) {
                return APIResponse.returnFail("支付系统检查到提现申请号为["+withdrawNo+"]的提现申请，系统已经付款");
            }
        }
        updateWithdrawApplyPayInfo(Integer.valueOf(payInfo.getWithdrawNo()), payInfo.getPayOpInfo()); //记录操作人信息

        //获取公司的微信商户账户信息
        Integer accountVersion = apply.getAppVersion();
        APIResponse<WeichatAccount> accountResp = payService.getWeichatAccount(accountVersion==null?"2":String.valueOf(accountVersion), PayWayEnum.PAY_WAY_WEICHAT.getPayId());
        if (!accountResp.isRet()) {
            return accountResp;
        }
        WeichatAccount weichatAccount = accountResp.getData();

        //调用微信企业支付接口
        TransferFundReqData data = new TransferFundReqData();
        data.setMch_appid(weichatAccount.getAppId());
        data.setMchid(weichatAccount.getMchId());
        data.setOpenid(openid);
        data.setAmount(payAmount.intValue());
        data.setPartner_trade_no(withdrawNo);
        data.setNonce_str(RandomStringGenerator.getRandomStringByLength(32));
        data.setRe_user_name(apply.getWithdrawUserName()); //强制校验提现人真实姓名
        data.setDesc(desc);
        data.setSpbill_create_ip("127.0.0.1");
        String sign = null;
        try {
            sign = Signature.getSign(data, weichatAccount.getWxKey());
        } catch (IllegalAccessException e) {
            e.printStackTrace();
        }
        data.setSign(sign);
        data.setSslCertificate(new ByteArrayInputStream(weichatAccount.getCertData()));
        WeichatServiceApi weichatServiceApi = new WeichatServiceApi();
        TransferFundResData resData = weichatServiceApi.transferFund(data);
        logger.info("调用微信付款，返回：{}", JSON.toJSON(resData));

        //处理付款结果
        WithdrawTransferNotify notify = new WithdrawTransferNotify();
        notify.setSourceSystemCode(apply.getSourceSystemCode());
        notify.setSourceBusinessCode(apply.getSourceBusinessCode());
        notify.setWithdrawNo(withdrawNo);
        notify.setApplyNo(apply.getWithdrawApplyNo());
        notify.setAmount(payAmount.divide(new BigDecimal(100), 2));    //回调返回单位为元
        notify.setAccountNo(openid);
        notify.setName(apply.getWithdrawUserName());
        notify.setCompletedTime(new SimpleDateFormat("yyyy-MM-dd HH:mm:ss").format(new Date()));

        String resultCode = resData.getReturn_code();
        if ("SUCCESS".equals(resultCode)
                && "SUCCESS".equals(resData.getResult_code())) {
            //更新提现申请记录
            apply.setTsnNo(resData.getPayment_no());
            apply.setAuditStatus((byte) 1);
            apply.setStatus((byte) 2); //转账成功
            apply.setResult("付款成功");
            apply.setPayAmount(payAmount.divide(new BigDecimal(100), 2));  //实际支付金额，变成元
            withdrawApplyMapper.updateByPrimaryKeySelective(apply);

            //发送MQ消息给业务系统，通知付款成功信息
            notify.setTsn(resData.getPayment_no());
            notify.setTag(true);
            notify.setReason("付款成功");
            sendNotify(apply.getNotifyUrl(), notify, resData.getNonce_str());

            return APIResponse.returnSuccess(resData.getPayment_no()); //企业付款成功，返回的微信订单号
        } else {
            String error = resData.getResult_code() + resData.getReturn_msg();
            //更新提现申请记录
            apply.setAuditStatus((byte) 1);
            apply.setResult(error);
            if ("NOTENOUGH".equals(resultCode)||resData.getReturn_msg().equals("对同一用户转账操作过于频繁,请稍候重试.")){ //内部原因，余额不足，可重新付款
                apply.setStatus((byte)3);
                withdrawApplyMapper.updateByPrimaryKeySelective(apply);
            }else {
                apply.setStatus((byte) 4); //外部原因，转账失败
                withdrawApplyMapper.updateByPrimaryKeySelective(apply);

                //发送MQ消息给业务系统，通知付款失败信息
                notify.setTag(false);
                notify.setReason(error);
                sendNotify(apply.getNotifyUrl(), notify, resData.getNonce_str());
            }

            return APIResponse.returnFail(error);
        }
    }


    /**
     * 批量付款，支付宝批量付款到支付宝账户有密接口，生成提交表单，返回html表单给前端提交批量付款信息
     */
    @Override
    @Transactional(rollbackFor = Exception.class)
    public APIResponse getBatchTransferFundByAlipayHtmlForm(ReqWithdrawFormData reqWithdrawTransferData) {

        //1. 生成付款详细信息, 格式为：流水号1^收款方账号1^收款账号姓名1^付款金额1^备注说明1|流水号2^收款方账号2^收款账号姓名2^付款金额2^备注说明2。
        StringBuilder payDetailData = new StringBuilder();
        List<WithdrawPayInfo> withdrawPayInfos = reqWithdrawTransferData.getWithdrawPayInfos();
        if (withdrawPayInfos == null || withdrawPayInfos.size() == 0){
            return APIResponse.returnFail("无付款信息");
        }

        int batchNum = withdrawPayInfos.size();
        BigDecimal batchFee = BigDecimal.ZERO;

        StringBuilder withdrawNos = new StringBuilder();
        for (int i = 0; i < batchNum; i++) {
            WithdrawPayInfo payInfo = withdrawPayInfos.get(i);
            batchFee = batchFee.add(payInfo.getAmount());
            //单条付款信息
            StringBuilder sb = new StringBuilder();
            sb.append(payInfo.getWithdrawNo());  //流水号用支付系统生成的提现申请流水号
            sb.append("^");
            sb.append(payInfo.getAccountNo());
            sb.append("^");
            sb.append(payInfo.getName());
            sb.append("^");
            BigDecimal payAmount = payInfo.getPayAmount();
            sb.append(payAmount);
            updateWithdrawApplyPayInfo(Integer.valueOf(payInfo.getWithdrawNo()), payInfo.getPayOpInfo());
            sb.append("^");
            sb.append(new SimpleDateFormat("yyyy-MM-dd HH:mm:ss").format(payInfo.getApplyTime())); //备注为申请提现时间
            payDetailData.append(sb.toString());
            withdrawNos.append(payInfo.getWithdrawNo());
            if (i != batchNum - 1) {
                payDetailData.append("|");
                withdrawNos.append(",");
            }
        }

        //2. 生成付款批次号
        String seqNo = CommonUtils.generateOrderNo(1000);
        if (seqNo.length() > 24) {
            seqNo = seqNo.substring(0, 23);
        }
        String batchNo = UtilDate.getDate() + seqNo; //保证唯一

        //3. 获取公司的支付宝账户信息
        APIResponse<AlipayAccount> accountResp = payService.getAlipayAccount("2", PayWayEnum.PAY_WAY_ALIPAY.getPayId());
        if (!accountResp.isRet()) {
            return accountResp;
        }
        AlipayAccount alipayAccount = accountResp.getData();

        //4. 组装支付宝批量付款到支付宝账户有密接口所需参数
        AliPayBatchTransReqData reqData = new AliPayBatchTransReqData();
        reqData.setPartner(alipayAccount.getPartner());
        reqData.set_input_charset(alipayAccount.getInputCharset()); // UTF-8
        reqData.setSign_type(alipayAccount.getSignType());
        reqData.setNotify_url(withdrawNotifyUrl);
        reqData.setAccount_name("深圳市泉眼网络科技有限公司");
        reqData.setDetail_data(payDetailData.toString());
        reqData.setBatch_no(batchNo);
        reqData.setBatch_num(String.valueOf(batchNum));
        reqData.setBatch_fee(String.valueOf(batchFee.doubleValue()));
        reqData.setEmail(alipayAccount.getSeller());
        reqData.setPay_date(UtilDate.getDate());

        //5. 生成批量付款请求HTML表单
        AlipayConfig alipayConfig = new AlipayConfig.Builder()
                .setKey(alipayAccount.getAliKey())
                .build();
        String result = AlipaySubmit.buildRequest(ObjectUtil.objectToMapString(reqData),
                reqWithdrawTransferData.getFormMethod(), reqWithdrawTransferData.getFormSubmitButtonName(), alipayConfig);

        //6. 生成提现记录
        WithdrawRecord withdrawRecord = new WithdrawRecord();
        withdrawRecord.setBatchNo(batchNo);
        withdrawRecord.setBatchNum(batchNum);
        withdrawRecord.setWithdrawNo(withdrawNos.toString());
        withdrawRecord.setStatus((byte) 0); //返回了提交表单，跳到支付宝批量付款页面，但不一定付了款
        withdrawRecordMapper.insert(withdrawRecord);

        //7. 返回结果
        Map<String, String> resultMap = new HashMap<>();
        resultMap.put("batchNo", batchNo);      //付款批次号
        resultMap.put("form", result);          //表单信息
        return APIResponse.returnSuccess(resultMap);
    }

    @Override
    @Valid
    public APIResponse<List<RespBankInfo>> getBankList() {
        List<RespBankInfo> respBankInfoList = eBankMapper.getBankList();
        return APIResponse.returnSuccess(respBankInfoList);
    }

    @Override
    public int posUnionPayExcepton(ReqPosUnionPayExcepVo unionPayExcepVo) {
        logger.info("订单号：{}, 银联POS人工确认收款记录{}", unionPayExcepVo.getOrderNo(), GsonUtils.toJson(unionPayExcepVo));
        TbUnionPosRecord record = new TbUnionPosRecord();
        record.setOperator(unionPayExcepVo.getOperator());
        record.setOrderNo(unionPayExcepVo.getOrderNo());
        record.setReferenceNo(unionPayExcepVo.getReferenceNo());
        record.setOptType(UnionPosOptType.PAY_SUCCESS_BY_MANUAL_CONFIRM.getOptType());

        return tbUnionPosRecordMapper.insertSelective(record);
    }

}